#include <iostream>
#include <memory>

/*
这个模板类存在的问题：
1.
构造函数中，使用new不仅申请了空间，还调用了构造函数，但实际上用户仅仅想申请空间而已。
正确做法：应该仅开辟内存，而不构造对象
2.
析构函数中，使用delete会把容器中所有内存都当作对象，调用容器存储对象的析构函数，然后释放空间。
正确做法：应该仅析构合法对象（仍在有效范围内的容器内对象），然后释放所有空间。
3.
pop_back函数中，仅修改了_last指针，而没有析构对象。应当析构该对象，但不应该释放容器内存

容器的空间配置器的作用：
1. 内存开辟
2. 内存释放
3. 对象构造
4. 对象析构
*/
template <typename T> class Allocator {
public:
  T *allocate(size_t size) { return (T *)malloc(sizeof(T) * size); }

  void deallocate(void *p) { free(p); }

  void construct(T *p, const T &val) { new (p) T(val); }

  void destroy(T *p) { p->~T(); }
};

/*
容器底层 内存开辟 内存释放 对象构造 对象析构 都通过allocator实现
*/
template <typename T, typename Alloc = Allocator<T>> class Vector {
public:
  Vector(size_t size = 10) {
    // 需要把内存开辟和构造对象分开处理，在这个地方，应当仅是开辟空间，而不构造对象
    // _first = new T[size];
    _first = _allocator.allocate(size);
    _last = _first;
    _end = _first + size;
  }

  ~Vector() {
    // 仅析构容器中有效的元素，然后释放_first指针指向的堆内存
    // delete[] _first;
    for (T *p = _first; p != _last; ++p) {
      _allocator.destroy(p); // 析构 _first指针指向的有效元素
    }
    _allocator.deallocate(_first); // 释放整块内存
    _first = _last = _end = nullptr;
  }

  Vector(const Vector<T> &other) {
    int cap = other._end - other._first;
    int len = other._last - other._first;
    // _first = new T[cap];
    _first = _allocator.allocate(cap);
    for (int i = 0; i < len; i++) {
      // _first[i] = other._first[i];
      _allocator.construct(_first + i, other._first[i]);
    }
    _last = _first + len;
    _end = _first + cap;
  }

  Vector(Vector<T> &&other) {
    _first = other._first;
    _last = other._last;
    _end = other._end;
    other._first = other._last = other._end = nullptr;
  }

  Vector<T> &operator=(const Vector<T> &other) {
    if (this == &other) {
      return *this;
    }
    // delete[] _first;
    for (T *p = _first; p != _last; ++p) {
      _allocator.destroy(p); // 析构 _first指针指向的有效元素
    }
    _allocator.deallocate(_first); // 释放整块内存

    int cap = other._end - other._first;
    int len = other._last - other._first;
    // _first = new T[cap];
    _first = _allocator.allocate(cap);
    for (int i = 0; i < len; i++) {
      // _first[i] = other._first[i];
      _allocator.construct(_first + i, other._first[i]);
    }
    _last = _first + len;
    _end = _first + cap;
    return *this;
  }

  Vector<T> &operator=(Vector<T> &&other) {
    if (this == &other) {
      return *this;
    }
    delete[] _first;
    _first = other._first;
    _last = other._last;
    _end = other._end;
    other._first = other._last = other._end = nullptr;
    return *this;
  }

  T &operator[](size_t idx) { return _first[idx]; }

  void push_back(const T &val) {
    if (_last == _end)
      resize();
    // *_last = val;
    _allocator.construct(_last, val);
    _last++;
  }

  void pop_back() {
    // 只需要析构对象 但不释放内存
    if (_last == _first)
      return;
    // --_last;
    --_last;
    _allocator.destroy(_last);
  }

  T back() const { return *(_last - 1); }
  size_t size() const { return _last - _first; }
  bool empty() const { return _last == _first; }

private:
  void resize() {
    int cap = _end - _first;
    // T *ptmp = new T[cap * 2];
    T *ptmp = _allocator.allocate(cap * 2);
    for (int i = 0; i < cap; i++) {
      // ptmp[i] = _first[i];
      _allocator.construct(ptmp + i, _first[i]);
    }

    // delete[] _first;
    for (T *p = _first; p != _last; ++p) {
      _allocator.destroy(p); // 析构 _first指针指向的有效元素
    }
    _allocator.deallocate(_first); // 释放整块内存

    _first = ptmp;
    _last = _first + cap;
    _end = _first + 2 * cap;
  }

private:
  T *_first;
  T *_last;
  T *_end;
  Alloc _allocator;
};

class Foo {
public:
  Foo() { std::cout << "Foo()" << std::endl; }
  Foo(const Foo &other) { std::cout << "Foo(const Foo&)" << std::endl; }
  ~Foo() { std::cout << "~Foo()" << std::endl; }
};

int main() {
  Vector<Foo> v;
  Foo f1, f2, f3;
  v.push_back(f1);
  v.push_back(f2);
  v.push_back(f3);
  v.push_back(Foo{});
  v.push_back(Foo{});
  v.push_back(Foo{});
}